import React from "react";
import { BaseElmt } from "@/module-00-codebase/pkg-03-abstract";
import { Bi, RootContainer, View } from "@/module-00-codebase/pkg-01-container";
import { aw, asyncWait, pendingResolve, Throwable } from "@/module-00-codebase/pkg-02-tool";
import * as style from "./style";
import { consts } from "@/module-00-codebase/pkg-00-const";
export class Cover {
  public async on(container: BaseElmt<any> = RootContainer.secondary) {
    return asyncWait(
      async () => {
        container = findRootContainer(container);
        const last = findLastContainer(container);
        const coverContainer = pendingResolve<BaseElmt<any>>();
        const cover = pendingResolve<BaseElmt<any>>();
        Bi.renderer.render(<TransCover params={[coverContainer.resolve]} init={cover.resolve} key={Bi.utils.uuid()} />, last);
        bindContainerWithCover(last, await cover);
        return await coverContainer;
      },
      container,
      "cover-on"
    );
  }
  public async off(container: BaseElmt<any> = RootContainer.secondary) {
    return asyncWait(
      async () => {
        container = findRootContainer(container);
        await unBindContainerWithCover(container);
      },
      container,
      "cover-off"
    );
  }
}
export const dependencies = () => ["RootRenderer", "Renderer"];
const bindContainerWithCover = (container: BaseElmt<any>, cover: BaseElmt<any>) => {
  container = findLastContainer(container);
  (container as any)[NEXT] = cover;
  (cover as any)[PREV] = container;
};
const unBindContainerWithCover = async (container: BaseElmt<any>) => {
  const cover = findLastContainer(container) as TransCover;
  const prev = findPrevContainer(cover);
  await cover.close();
  delete (cover as any)[PREV];
  delete (prev as any)[NEXT];
  Bi.renderer.render(null, prev);
};
const findLastContainer = (container: BaseElmt<any>): BaseElmt<any> => findChainByKey(container, NEXT);
const findRootContainer = (container: BaseElmt<any>): BaseElmt<any> => findChainByKey(container, PREV);
const findPrevContainer = (container: BaseElmt<any>): BaseElmt<any> => (findLastContainer(container) as any)[PREV] || Throwable("Cover is off before on.");

class TransCover extends BaseElmt<[(elmt: BaseElmt<any>) => void]> {
  public elmtView(): JSX.Element | null {
    return (
      // container
      <Layout params={[]} className={[style.container, style.fadein, this.elmtRead("closed") ? style.fadeout : undefined]}>
        {/* full container cover */}
        <Layout params={[]} className={style.cover} />
        {/*  */}
        <Empty params={[]} init={this.getParams(0)} />
      </Layout>
    );
  }
  public async close() {
    await aw(consts.gradientSeconds);
    this.elmtWrite("closed", true);
    await aw(consts.gradientSeconds);
  }
}
const PREV = Symbol();
const NEXT = Symbol();
const findChainByKey = (container: BaseElmt<any>, key: any): BaseElmt<any> => {
  let cache = container;
  while (!!(cache = (cache as any)[key])) container = cache;
  return container;
};
class Layout extends BaseElmt<[]> {
  public elmtView(): JSX.Element | null {
    return <View>{this.props.children}</View>;
  }
}
class Empty extends BaseElmt<[]> {
  public elmtView(): JSX.Element | null {
    return <>{this.props.children}</>;
  }
}
